#pragma once

#include <functional>
#include <memory>

#include "../utility/Noncopyable.h"
#include "../utility/Timestamp.h"

// .h用不到不要包含头文件暴露更多信息，用前置声明就可以了
// EventLoop参数指针不影响
// Timestamp参数不是指针需要类型信息就需要头文件
class EventLoop;

// EventLoop：reactor；Poller：多路复用器；Channel：事件+事件处理器
// Channel通道：fd+感兴趣的event+poller返回的具体事件
class Channel : Noncopyable
{
public:
    using ReadEventCallback = std::function<void(Timestamp)>;
    using EventCallback = std::function<void()>; // muduo使用typedef

    Channel(EventLoop *loop, int fd); // 属于的loop，封装的fd
    ~Channel() = default;

    EventLoop *getEventLoop();
    int getFd() const;
    void setRevents(int revt);
    int getEvents() const;
    void setStatus(int status);
    int getStatus() const;

    bool isNoneEvent() const;
    bool isReadEvent() const;
    bool isWriteEvent() const;

    void enableReadEvent();
    void disableReadEvent();
    void enableWriteEvent();
    void disableWriteEvent();
    void disableAllEvent();

    // OPTIMIZE: 回调函数形参传右值引用（非常量左值不能接右值），不保证回调函数具体内容不用const
    void setReadCallback(ReadEventCallback &&cb);
    void setWriteCallback(EventCallback &&cb);
    void setCloseCallback(EventCallback &&cb);
    void setErrorCallback(EventCallback &&cb);

    // OPTIMIZE: 时间戳形参传引用，不保证回调函数具体内容不用const
    void handleEvent(Timestamp &recvTime);

    // TcpConnection创建channel，向channel注册TcpConnection::callbacks()
    // channel绑定TcpConnection，防止TcpConnection失效执行TcpConnection::::callbacks()失败
    // 弱智能指针绑定强智能指针：避免循环引用+观察对象生命周期
    void tieChannel(const std::shared_ptr<void> &obj);
    // loop删除channel
    void removeChannel();

private:
    // channel通过loop去改变poller的epoll_ctl()
    void updateChannal();
    void handleEventWithGuard(Timestamp &recvTime);

    // static const int -> enum class ×，因为要表示EPOLLIN这样的位事件
    static const int kNoneEvent;
    static const int kReadEvent;
    static const int kWriteEvent;

    EventLoop *loop_; // 属于的loop
    const int fd_;    // 封装的fd
    int events_;      // 感兴趣的事件
    int revents_;     // Poller返回的具体事件
    // 原注释：use by Poller.
    // 表示channel在poller中的状态：未添加，已添加，已删除
    // poller根据channel不同状态执行不同操作，类似状态机状态转换
    // int index_;
    int status_;

    // 防止手动remove channel后还在使用，进行跨线程对象生存状态监听
    // 提升为强指针成功就存在，否则不存在
    std::weak_ptr<void> tiePtr_;
    bool isTied_;

    // 因为channel通道里可获知fd最终发生的具体的事件events，所以它负责调用具体事件的回调操作
    ReadEventCallback readCallback_;
    EventCallback writeCallback_;
    EventCallback closeCallback_;
    EventCallback errorCallback_;
};